package com.maxlen.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.maxlen.common.rabbitMQConstant.WareRabbitMQConstant;
import com.maxlen.common.utils.PageUtils;
import com.maxlen.common.utils.R;
import com.maxlen.ware.enume.WareOrderTaskDetailEnum;
import com.maxlen.ware.dao.WareSkuDao;
import com.maxlen.ware.entity.WareOrderTaskDetailEntity;
import com.maxlen.ware.entity.WareOrderTaskEntity;
import com.maxlen.ware.entity.WareSkuEntity;
import com.maxlen.ware.entity.to.OrderTO;
import com.maxlen.ware.entity.to.SkuHasStockTO;
import com.maxlen.ware.entity.to.WareSkuLockTO;
import com.maxlen.ware.entity.vo.SkuIdAndWareIdVO;
import com.maxlen.ware.entity.vo.WareSkuPageParamsVO;
import com.maxlen.ware.enume.OrderStatusEnum;
import com.maxlen.ware.exception.NoStockException;
import com.maxlen.ware.feign.OrderFeignService;
import com.maxlen.ware.service.WareOrderTaskDetailService;
import com.maxlen.ware.service.WareOrderTaskService;
import com.maxlen.ware.service.WareSkuService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private WareOrderTaskService wareOrderTaskService;

    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderFeignService orderFeignService;

    @Override
    public PageUtils queryPage(WareSkuPageParamsVO params) {
        LambdaQueryWrapper<WareSkuEntity> wrapper = new LambdaQueryWrapper<>();

        String skuId = params.getSkuId();
        if(StringUtils.hasText(skuId)){
            wrapper.eq(WareSkuEntity::getSkuId, skuId);
        }

        String wareId = params.getWareId();
        if(StringUtils.hasText(wareId)){
            wrapper.eq(WareSkuEntity::getWareId, wareId);
        }

        IPage<WareSkuEntity> page = this.page(
                new Page<>(params.getPage(), params.getLimit()),
                wrapper
        );

        return new PageUtils(page);
    }

    @Override
    public List<SkuHasStockTO> getSkuHasStock(List<Long> skuIdList) {
        List<SkuHasStockTO> skuIds = baseMapper.getSkuHasStock(skuIdList);
        return skuIds;
    }

    /**
     * 锁定库存
     * @param wareSkuLockTO
     * @return
     */
    @Override
    @Transactional
    public void lockStock(WareSkuLockTO wareSkuLockTO) {

        // 保存工作单
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(wareSkuLockTO.getOrderSn());
        wareOrderTaskService.save(wareOrderTaskEntity);

        List<WareSkuLockTO.LockStockCountTO> lockStockCountTOList = wareSkuLockTO.getLockStockCountTOList();
        List<Long> skuIdList = lockStockCountTOList.stream().map(WareSkuLockTO.LockStockCountTO::getSkuId).collect(Collectors.toList());
        List<SkuIdAndWareIdVO> skuIdAndWareIdVOList = baseMapper.getSkuIdAndWareId(skuIdList);

        for (WareSkuLockTO.LockStockCountTO lockStockCountTO : lockStockCountTOList) {

            // 判断商品在哪些仓库有库存
            List<Long> wareIdList = skuIdAndWareIdVOList.stream()
                    .filter((item) -> {
                        return lockStockCountTO.getSkuId().equals(item.getSkuId());
                    })
                    .map(SkuIdAndWareIdVO::getWareId).collect(Collectors.toList());

            if(wareIdList.isEmpty()){
                System.out.println(lockStockCountTO.getSkuId());
                throw new NoStockException(lockStockCountTO.getSkuId());
            }


            // 锁定库存
            boolean reallyLockStock = false;
            for (Long wareId : wareIdList) {
                int lockStock = baseMapper.lockStock(lockStockCountTO.getSkuId(), wareId, lockStockCountTO.getCount());

                if(lockStock > 0){
                    reallyLockStock = true;

                    // 保存工作单详情
                    WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
                    wareOrderTaskDetailEntity.setSkuId(lockStockCountTO.getSkuId());
                    wareOrderTaskDetailEntity.setWareId(wareId);
                    wareOrderTaskDetailEntity.setSkuName(lockStockCountTO.getSkuId().toString());
                    wareOrderTaskDetailEntity.setTaskId(wareOrderTaskEntity.getId());
                    wareOrderTaskDetailEntity.setSkuNum(lockStockCountTO.getCount());
                    wareOrderTaskDetailEntity.setLockStatus(WareOrderTaskDetailEnum.LOCKING.getCode());
                    wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);

                    // 发送给 MQ，延迟判断是否需要解锁库存
                    rabbitTemplate.convertAndSend(
                            WareRabbitMQConstant.WARE_EVENT_EXCHANGE,
                            WareRabbitMQConstant.WARE_STOCK_DELAY_BINDING,
                            wareOrderTaskDetailEntity.getId());

                    break;
                }
            }

            if(!reallyLockStock){
                System.out.println(lockStockCountTO.getSkuId());
                throw new NoStockException(lockStockCountTO.getSkuId());
            }
        }
    }

    /**
     * 判断是否需要解锁库存
     * @param wareOrderTaskDetailId
     */
    @Override
    @Transactional
    public void isUnlockStock(Long wareOrderTaskDetailId){
        /**
         * 查询工作单：
         *      1、存在：
         *          查询订单并判断订单是否为取消状态：
         *              1、存在且不是取消状态：不需要解锁库存
         *              2、存在且是取消状态 或 不存在：解锁库存
         *      2、不存在：不需要解锁库存
         */
        WareOrderTaskDetailEntity wareOrderTaskDetailServiceById = wareOrderTaskDetailService.getById(wareOrderTaskDetailId);
        if(!ObjectUtils.isEmpty(wareOrderTaskDetailServiceById)){
            WareOrderTaskEntity wareOrderTaskServiceById = wareOrderTaskService.getById(wareOrderTaskDetailServiceById.getTaskId());
            if(!ObjectUtils.isEmpty(wareOrderTaskServiceById)){
                String orderSn = wareOrderTaskServiceById.getOrderSn();
                R orderStatus = orderFeignService.getOrderStatus(orderSn);
                if(orderStatus.isOk()){
                    OrderTO orderTO = orderStatus.getData(new TypeReference<OrderTO>() {});
                    // 判断订单是否存在，并且状态为已取消
                    if(ObjectUtils.isEmpty(orderTO) || Objects.equals(orderTO.getStatus(), OrderStatusEnum.CANCEL.getCode())){
                        if(wareOrderTaskDetailServiceById.getLockStatus().equals(WareOrderTaskDetailEnum.LOCKING.getCode())){
                            unlockStock(wareOrderTaskDetailServiceById.getSkuId(), wareOrderTaskDetailServiceById.getWareId(), wareOrderTaskDetailServiceById.getSkuNum(), wareOrderTaskDetailServiceById.getId());
                        }
                    }
                }else{
                    throw new RuntimeException("远程订单系统异常");
                }
            }
        }
    }

    /**
     * 判断是否需要解锁库存
     * @param orderSn
     */
    @Override
    @Transactional
    public void isUnlockStock(byte[] orderSn) {
        String orderSnId = new String(orderSn);
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getOne(new LambdaQueryWrapper<WareOrderTaskEntity>().eq(WareOrderTaskEntity::getOrderSn, orderSnId));
        if(!ObjectUtils.isEmpty(wareOrderTaskEntity)){
            List<WareOrderTaskDetailEntity> wareOrderTaskDetailEntityList = wareOrderTaskDetailService.list(
                    new LambdaQueryWrapper<WareOrderTaskDetailEntity>()
                            .eq(WareOrderTaskDetailEntity::getTaskId, wareOrderTaskEntity.getId())
                            .eq(WareOrderTaskDetailEntity::getLockStatus, WareOrderTaskDetailEnum.LOCKING.getCode())
            );
            R orderStatus = orderFeignService.getOrderStatus(orderSnId);
            if(orderStatus.isOk()){
                OrderTO orderTO = orderStatus.getData(new TypeReference<OrderTO>() {});
                // 判断订单是否存在，并且状态为已取消
                if(ObjectUtils.isEmpty(orderTO) || Objects.equals(orderTO.getStatus(), OrderStatusEnum.CANCEL.getCode())){
                    for (WareOrderTaskDetailEntity wareOrderTaskDetailEntity : wareOrderTaskDetailEntityList) {
                        // 判断库存工作单状态是否为已锁定
                        if(wareOrderTaskDetailEntity.getLockStatus().equals(WareOrderTaskDetailEnum.LOCKING.getCode())){
                            unlockStock(
                                    wareOrderTaskDetailEntity.getSkuId(),
                                    wareOrderTaskDetailEntity.getWareId(),
                                    wareOrderTaskDetailEntity.getSkuNum(),
                                    wareOrderTaskDetailEntity.getId());
                        }
                    }
                }
            }else{
                throw new RuntimeException("远程订单系统异常");
            }
        }
    }

    /**
     * 解锁库存
     * @param skuId 商品 id
     * @param wareId 库存 id
     * @param count 数量
     * @param taskDetailId 任务详情表 id
     */
    private void unlockStock(Long skuId, Long wareId, Integer count, Long taskDetailId){
        baseMapper.unlockStock(skuId, wareId, count);

        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
        wareOrderTaskDetailEntity.setId(taskDetailId);
        wareOrderTaskDetailEntity.setLockStatus(WareOrderTaskDetailEnum.UNLOCKING.getCode());
        wareOrderTaskDetailService.updateById(wareOrderTaskDetailEntity);
    }

}
